#include "contacts.h"

void check_capacity(Contacts* con){
    assert(con);
    if (con->sz == con->capacity){
        //增加容量
        PeoInfo* ptr = (PeoInfo*)realloc(con->data, (con->capacity + INC_SZ)*sizeof(PeoInfo));
        if (NULL == ptr){
            perror("check_capacity::realloc");
            return;
        }
        con->data = ptr;
        con->capacity += INC_SZ;
        printf("增容成功\n");
    }
}

void InitContacts(Contacts* con){
    assert(con);
    con->sz = 0;
    PeoInfo* ptr = (PeoInfo*)calloc(DEFAULT_SZ, sizeof(PeoInfo));
    if (NULL == ptr){
        perror("InitContacts::calloc");
        return;
    }
    con->data = ptr;
    con->capacity = DEFAULT_SZ;

    LoadContacts(con);
}

void LoadContacts(Contacts* con){
    assert(con);
    //读数据
    //1.打开文件
    FILE* pf = fopen("contacts.txt", "rb");
    if (NULL == pf){
        perror("LoadContacts");
        return;
    }
    else {
        //2.读数据
        PeoInfo tmp = { 0 };
        int i = 0;
        while (fread(&tmp, sizeof(PeoInfo), 1, pf)){
            //增容
            check_capacity(con);
            con->data[i] = tmp;
            con->sz++;
            i++;
        }
        fclose(pf);
        pf = NULL;
    }
}

void AddContacts(Contacts* con){
    assert(con);
    int input = 0;

flag:
        check_capacity(con);        
        printf("请输入联系人的姓名:>");
        scanf("%s", con->data[con->sz].name);
        printf("请输入联系人的年龄:>");
        scanf("%d", &con->data[con->sz].age);
        printf("请输入联系人的性别:>");
        scanf("%s",con->data[con->sz].sex);
        printf("请输入联系人的地址:>");
        scanf("%s",con->data[con->sz].addr);
        printf("请输入联系人的电话号码:>");
        scanf("%s",con->data[con->sz].tele);
        con->sz++;
        printf("添加成功\n");

        printf("1.keep adding 0. exit\n");
        printf("请选择:>");
        scanf("%d", &input);
        if (1 == input) 
            goto flag;
        else 
            return;

}

//通过姓名定位联系人
int FindByName(const Contacts* con, char name[]){
    assert(con);

    int i = 0;
    for (i = 0; i < con->sz; i++){
        if (strcmp(con->data[i].name, name) == 0){
            return i;
        }
    }
    return -1;
}

void DelContacts(Contacts* con){
    assert(con);

    char name[NAME_MAX] = { 0 };
    if (0 == con->sz){
        printf("通讯录为空，无法删除\n");
        return;
    }
    
    printf("请输入要删除的联系人的姓名:>");
    scanf("%s", name);
    int pos =FindByName(con, name);
    if( -1 == pos){
        printf("要删除的人不存在\n");
        return;
    }

    int i = 0;
    for (i = pos; i < con->sz - 1; i++){
        con->data[i] = con->data[i + 1];
    }
    con->sz--;
    printf("删除成功\n");
}

void SearchContacts(Contacts* con){
    assert(con);
    
    char name[NAME_MAX] = { 0 };
    if (0 == con->sz){
        printf("通讯录为空，无法查找\n");
        return;
    }
    
    printf("请输入要查找的联系人的姓名:>");
    scanf("%s", name);
    int pos =FindByName(con, name);
    if( -1 == pos){
        printf("要查找的人不存在\n");
        return;
    }
    printf("%-20s\t%-5s\t\t%-5s\t\t%-30s %-12s\n", "姓名", "年龄", "性别", "地址", "电话号码");
    printf("%-20s\t%-5d\t\t%-5s\t\t%-30s%-12s\n",  con->data[pos].name, 
                                                con->data[pos].age, 
                                                con->data[pos].sex, 
                                                con->data[pos].addr, 
                                                con->data[pos].tele);

}

void ModifyContacts(Contacts* con){
    assert(con);
    
    char name[NAME_MAX] = { 0 };
    if (0 == con->sz){
        printf("通讯录为空，无法修改\n");
        return;
    }
    
    printf("请输入要修改的联系人的姓名:>");
    scanf("%s", name);
    int pos =FindByName(con, name);
    if( -1 == pos){
        printf("要修改的人不存在\n");
        return;
    }
    printf("请输入联系人的姓名:>");
    scanf("%s", con->data[pos].name);
    printf("请输入联系人的年龄:>");
    scanf("%d", &con->data[pos].age);
    printf("请输入联系人的性别:>");
    scanf("%s",con->data[pos].sex);
    printf("请输入联系人的地址:>");
    scanf("%s",con->data[pos].addr);
    printf("请输入联系人的电话号码:>");
    scanf("%s",con->data[pos].tele);
    printf("修改成功\n");

}

void ShowContacts(Contacts* con){
    assert(con);
    int i = 0;
    printf("%-20s\t%-5s\t\t%-5s\t\t%-30s %-12s\n", "姓名", "年龄", "性别", "地址", "电话号码");
    for (i = 0; i < con->sz; i++){
        printf("%-20s\t%-5d\t\t%-5s\t\t%-30s%-12s\n",  con->data[i].name, 
                                                con->data[i].age, 
                                                con->data[i].sex, 
                                                con->data[i].addr, 
                                                con->data[i].tele);
    }
}

//以char类型指针，每次交换一个字节的数据，确保能交换任意类型数据
static void Swap(char* elem1, char* elem2, size_t width){
    size_t i = 0;
    for(i = 0; i < width; i++){
        char tmp = *(elem1 + i);
        *(elem1 + i) = *(elem2 + i);
        *(elem2 + i) = tmp;
    }
}

//通过联系人的姓名进行排序
static int PeoContByName_cmp(const void* elem1, const void* elem2){
    return strcmp(((PeoInfo*)elem1)->name,((PeoInfo*)elem2)->name);
}

//利用冒泡排序模拟qsort库函数对联系人进行排序
static void bubblesort(void* base, size_t sz, size_t width, int (*cmp)(void* ,void* )){
    size_t i = 0;    
    for(i = 0; i < sz; i++){
        for(size_t j = 0; j < sz - 1 - i;j++){
            if(cmp((char*)base + j * width,(char *)base + (j + 1) * width) > 0){
                Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
            }                
        }
    }
}

void SortContacts(Contacts* con){
    assert(con);
    bubblesort(con->data, con->sz, sizeof(con->data[0]), (void*) PeoContByName_cmp);
    printf("根据联系人的姓名排序成功\n");
}

void SaveContacts(Contacts* con){
    assert(con);
	//写数据
	//1, 打开文件
	FILE*pf = fopen("contacts.txt", "wb");
	if (NULL == pf)
	{
		perror("SaveContact");
	}
	else
	{
		//写数据
		int i = 0;
		for (i = 0; i < con->sz; i++)
		{
			fwrite(con->data + i, sizeof(PeoInfo), 1, pf);
		}
		fclose(pf);
		pf = NULL;
		printf("保存成功\n");
	}
}

void DestroyContacts(Contacts* con){
    assert(con);

	free(con->data);
	con->data = NULL;
	con->capacity = 0;
	con->sz = 0;
	con = NULL;
}